<?php

namespace app\bll;

use app\enum\OrganizationType;
use app\validate\OrganCompany as ValidateOrganCompany;
use BlueM\Tree;
use BlueM\Tree\Serializer\HierarchicalTreeJsonSerializer;
use Exception;
use support\Db;

/**
 * 组织架构-单位
 */
class OrganCompany
{


    /**
     * 查询
     *
     * @param integer $id
     * @return array
     */
    public function find(int $id): array
    {
        $data =  Db::table('frame_organ_company')
            ->where('id', '=', $id)
            ->first();
        return $data === null ? [] : get_object_vars($data);
    }

    public function select(
        ?int $pid = null,
        ?int $type = null,
        string $order = " type desc,id  "
    ): array {
        return Db::table('frame_organ_company')
            ->when($pid !== null, function ($query) use ($pid) {
                return $query->where('pid', '=', $pid);
            })
            ->when($type !== null, function ($query) use ($type) {
                return $query->where('type', '=', $type);
            })
            ->orderByRaw($order)
            ->get()
            ->map(function ($value) {
                return (array)$value;
            })
            ->toArray();
    }

    /**
     * 添加机构
     *
     * @param array $data
     * @return integer
     */
    public function add(array $data): int
    {
        $ValidateOrganCompany = new ValidateOrganCompany();
        if (!$ValidateOrganCompany->check($data)) {
            throw new Exception($ValidateOrganCompany->getSimpleError());
        }

        return  Db::table('frame_organ_company')
            ->insertGetId($data);
    }


    /**
     * 修改
     *
     * @param integer $id
     * @param array $data
     * @return integer
     */
    public function edit(int $id, array $data): int
    {
        $ValidateOrganCompany = new ValidateOrganCompany();
        if (!$ValidateOrganCompany->check($data)) {
            throw new Exception($ValidateOrganCompany->getSimpleError());
        }

        return  Db::table('frame_organ_company')
            ->where('id', '=', $id)
            ->update($data);
    }

    public function delete(int $id)
    {
        Db::beginTransaction();
        try {
            //判断有无子级
            $childs = $this->select(pid: $id);
            if ($childs) {
                throw new Exception('请先删除子级');
            }

            Db::table('frame_organ_company')
                ->where('id', '=', $id)
                ->delete();

            Db::table('frame_user_basicinfo')
                ->where('organcompanyid', '=', $id)
                ->update([
                    'organcompanyid' => null
                ]);

            Db::commit();
        } catch (Exception $ex) {
            Db::rollBack();
            throw $ex;
        }
    }

    /**
     * 组织架构层级关系
     *
     * @return Tree|string
     */
    public function cascader(bool $onlycompany = false, bool $formatjson = true)
    {
        $tree = new Tree(
            $this->select(
                type: ($onlycompany ? OrganizationType::TYPE_COMPANY->value : null)
            ),
            [
                'rootId'         => 0,
                'id'             => 'id',
                'parent'         => 'pid',
                'jsonSerializer' => new HierarchicalTreeJsonSerializer()
            ]
        );

        return $formatjson ? json_encode($tree, JSON_UNESCAPED_UNICODE) : $tree;
    }


    /**
     * 某个站点下的组织结构
     *
     * @param integer $siteid
     * @param boolean $formatjson
     * @return array|string
     */
    public function cascaderBySiteid(int $siteid, bool $formatjson = true): array|string
    {
        $bllSite  = new Site();
        $siteinfo = $bllSite->find($siteid);
        $organid  = $siteinfo['orgid'];

        $tree = new Tree(
            $this->select(),
            [
                'rootId'         => 0,
                'id'             => 'id',
                'parent'         => 'pid',
                'jsonSerializer' => new HierarchicalTreeJsonSerializer()
            ]
        );

        $node = $tree->getNodeById($organid);
        $nodes = $node->getDescendantsAndSelf();
        return $formatjson ? json_encode($nodes, JSON_UNESCAPED_UNICODE) : $nodes;
    }



    /**
     * 自定义数据的层级
     *
     * @param array $data
     * @param boolean $formatjson
     * @return Tree|string
     */
    public function cusCascader(array $data, bool $formatjson = true): Tree|string
    {
        $tree = new Tree(
            $data,
            [
                'rootId'         => 0,
                'id'             => 'id',
                'parent'         => 'pid',
                'jsonSerializer' => new HierarchicalTreeJsonSerializer()
            ]
        );

        return $formatjson ? json_encode($tree, JSON_UNESCAPED_UNICODE) : $tree;
    }


    /**
     * 给组织架构添加图标和展开
     *
     * @return array
     */
    public function formatIconExpand(array $data): array
    {
        foreach ($data as $key => $d) {
            $data[$key]['title'] = $data[$key]['title']
                . ($d['type'] == OrganizationType::TYPE_COMPANY->value ? ' <i class=\"iconfont\" >&#xe623;</i>'
                    : ' <i class=\"iconfont\" >&#xe647;</i>');
            $data[$key]['spread'] = true;
        }
        return $data;
    }


    /**
     * 组织架构Tree
     *
     * @return Tree
     */
    public function tree(): Tree
    {
        return  new Tree(
            $this->select(),
            [
                'rootId'         => 0,
                'id'             => 'id',
                'parent'         => 'pid',
                'jsonSerializer' => new HierarchicalTreeJsonSerializer()
            ]
        );
    }

    /**
     * 获取自己和自己的父级
     *
     * @param array $menu
     * @return array
     */
    public function getAncestorsAndSelf(int $id, ?Tree $tree = null): array
    {
        if (!$tree) {
            $tree = $this->tree();
        }

        $node              = $tree->getNodeById($id);
        $ancestorsPlusSelf = $node->getAncestorsAndSelf();
        $parents           = [];
        foreach ($ancestorsPlusSelf as $ancestor) {
            $parents[] = $ancestor->toArray();
        }
        krsort($parents);
        return array_values($parents);
    }
}
